package sjtu.ist.warehouse4ws.tool;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringBufferInputStream;

import java.util.ArrayList;
import java.util.HashMap;

import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;



public class GenerateWadl {
	public HashMap<String,String> fs;

	public HashMap<String, String> getFs() {
		return fs;
	}

	public void setFs(HashMap<String, String> fs) {
		this.fs = fs;
	}

	public  String writeWadl(String outFile,String key) throws Exception{     //generate Wadl file
		ArrayList<String> list=parserXml(key);
	 
		ArrayList<String> list1=readPath(key);
		if (list1==null) return "缺少关联文件";
		String modelName=readModelName(key);
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc=db.newDocument();
		Element application=doc.createElement("application");   //create application node
		application.setAttribute("xmlns","http://"+modelName+"service.rest");
		doc.appendChild(application);
		
		Element grammars=doc.createElement("grammars");   //create grammars node
		if(list1!=null){                                    //if the root xml have no complexType, do nothing
		for(int k=0;k<list1.size();k++){
			String str=readModelName(list1.get(k));
			Element complexType=doc.createElement("complexType");
			complexType.setAttribute("name",str);
			grammars.appendChild(complexType);
			
			
			Element id=doc.createElement("element");
			id.setAttribute("name", "id");
			id.setAttribute("type", "string");
			complexType.appendChild(id);
			
			
			ArrayList<String> list3=parserXml(list1.get(k));
			for(int m=0;m<list3.size();m=m+2){
				Element ele=doc.createElement("element");
				ele.setAttribute("name",list3.get(m));
				ele.setAttribute("type", list3.get(m+1));
				
				complexType.appendChild(ele);
			}
		}
		}
		
		Element rootComplexType=doc.createElement("complexType");     //create root complexType
		
		rootComplexType.setAttribute("name",modelName);
		Element rootid=doc.createElement("element");
		rootid.setAttribute("name", "id");
		rootid.setAttribute("type", "string");
		rootComplexType.appendChild(rootid);
		for(int i=0;i<list.size();i=i+2){
			Element rootele=doc.createElement("element");
			rootele.setAttribute("name", list.get(i));
			rootele.setAttribute("type", list.get(i+1));
			rootComplexType.appendChild(rootele);
		}
		grammars.appendChild(rootComplexType);
		
		
		application.appendChild(grammars);
		
		
		Element resources=doc.createElement("resources");
		resources.setAttribute("base", "http://locahost:8080");
		application.appendChild(resources);
		Element resource=doc.createElement("resource");
		resource.setAttribute("path", "/"+modelName);
		resources.appendChild(resource);
		Element resource1=doc.createElement("resource");
		resource1.setAttribute("path", "/{id}");
		resources.appendChild(resource1);
		
		
		Element methodGet=doc.createElement("method");              //define get method
		methodGet.setAttribute("name", "Get");
		resource.appendChild(methodGet);
		Element request=doc.createElement("request");
		methodGet.appendChild(request);
		Element response=doc.createElement("response");
		methodGet.appendChild(response);
		Element representation=doc.createElement("representation");
		representation.setAttribute("mediaType", "application/xml");
		representation.setAttribute("element", modelName);
		response.appendChild(representation);
		Element fault=doc.createElement("fault");
		fault.setAttribute("staus", "400");
		fault.setAttribute("mediaType", "application/xml");
		response.appendChild(fault);
		
		Element methodPost=doc.createElement("method");               //define post method
		methodPost.setAttribute("name", "Post");
		resource.appendChild(methodPost);
		Element poRequest=doc.createElement("request");
		methodPost.appendChild(poRequest);
		Element reqRepresentation=doc.createElement("representation");
		reqRepresentation.setAttribute("mediaType", "application/xml");
		reqRepresentation.setAttribute("element", modelName);
		poRequest.appendChild(reqRepresentation);
		
		Element poResponse=doc.createElement("response");
		Element resRepresentation=doc.createElement("representation");
		resRepresentation.setAttribute("mediaType", "application/xml");
		resRepresentation.setAttribute("element", modelName);
		poResponse.appendChild(resRepresentation);
		methodPost.appendChild(poResponse);
	
		
		Element methodPut=doc.createElement("method");                //define put method
		methodPut.setAttribute("name", "Put");
		resource.appendChild(methodPut);
		Element putRequest=doc.createElement("request");
		methodPut.appendChild(putRequest);
		Element putRepresentation=doc.createElement("representation");
		putRepresentation.setAttribute("mediaType", "application/xml");
		putRepresentation.setAttribute("element", modelName);
		putRequest.appendChild(putRepresentation);
		
		Element putResponse=doc.createElement("response");
		Element putresRepresentation=doc.createElement("representation");
		putresRepresentation.setAttribute("mediaType", "application/xml");
		putresRepresentation.setAttribute("element", modelName);
		putResponse.appendChild(putresRepresentation);
		methodPut.appendChild(putResponse);
		
		
		
		
		Element paramid=doc.createElement("param");
		paramid.setAttribute("name", "id");
		paramid.setAttribute("type", "string");
		paramid.setAttribute("style", "template");
		resource1.appendChild(paramid);
		
		Element methodDelete=doc.createElement("method");             //difine delete method
		methodDelete.setAttribute("name", "Delete");
		resource1.appendChild(methodDelete);
		Element delRequest=doc.createElement("request");
		methodDelete.appendChild(delRequest);
		
		
		
		Element delResponse=doc.createElement("response");
		Element delRepresentation=doc.createElement("representation");
		delRepresentation.setAttribute("mediaType", "application/xml");
		delRepresentation.setAttribute("element", modelName);
		delResponse.appendChild(delRepresentation);
		methodDelete.appendChild(delResponse);
		
		
		return domDocToFile(doc,outFile,"UTF-8");	
	}
	
	public  String domDocToFile(Document doc, String fileName,String encoding) throws TransformerException{  //create the XML file
		TransformerFactory tfactory=TransformerFactory.newInstance();
		Transformer transformer=tfactory.newTransformer();
		Properties properties=transformer.getOutputProperties();
		properties.setProperty(OutputKeys.ENCODING, encoding);
		properties.setProperty(OutputKeys.METHOD, "xml");
		properties.setProperty(OutputKeys.INDENT, "yes");            //control line
		transformer.setOutputProperties(properties);
		
		DOMSource source=new DOMSource(doc);
		File file=new File(fileName);
		StreamResult result=new StreamResult(file);
		
		transformer.transform(source, result);

		return file.getAbsolutePath();
	}
	public ArrayList<String> parserXml(String key) throws SAXException, IOException ,FileNotFoundException{     //get the model attribute
		ArrayList<String> paramName=new ArrayList<String>();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = null;
		try {
			db = dbf.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Document doc = null;
	
		doc = db.parse(new StringBufferInputStream(fs.get(key)));
      
		NodeList nodelist= doc.getElementsByTagName("domain_model_attribute");  
		for(int i=0;i<nodelist.getLength();i++){
			Element dma=(Element)nodelist.item(i);
			NodeList str=dma.getElementsByTagName("enName");
			Element paramElement=(Element) str.item(0);
			Text paramNode=(Text) paramElement.getFirstChild();
			String str1=paramNode.getNodeValue();
			paramName.add(str1);
			
			
			NodeList str2=dma.getElementsByTagName("enType");
			Element e1=(Element) str2.item(0);
			Text t1=(Text) e1.getFirstChild();
			String str3=t1.getNodeValue();
			paramName.add(str3);

		}
		
		return paramName;
		
	}
	
	public String readModelName(String key) throws SAXException, IOException, FileNotFoundException  {               //get the complex name
	
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = null;
		try {
			db = dbf.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
		Document doc = null;
	//    BufferedInputStream bs=new BufferedInputStream(fs.get(key));
		doc = db.parse(new StringBufferInputStream(fs.get(key)));
	     
		NodeList nodelist = doc.getElementsByTagName("enName");
		Element dma = (Element) nodelist.item(0);
		Text paramNode = (Text) dma.getFirstChild();
		String str1 = paramNode.getNodeValue();
	
		return str1;
	}
//	public String readModelId(String xmlPath) throws Exception {               //get the complex typeid
//		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//		DocumentBuilder db = dbf.newDocumentBuilder();
//		File file = new File(xmlPath); 
//	
//		Document doc = db.parse(file);
//		NodeList nodelist = doc.getElementsByTagName("id");
//		Element dma = (Element) nodelist.item(0);
//		Text paramNode = (Text) dma.getFirstChild();
//		String str1 = paramNode.getNodeValue();
//		System.out.print(str1);
//		return str1;
//	}
	
	public ArrayList<String> readPath(String key) throws SAXException, IOException {                   //get children path
		ArrayList<String> pathList=new ArrayList();
	   // if (!fs.containsKey(key)) return null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = null;
		try {
			db = dbf.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Document doc = null;
		//BufferedInputStream bs=new BufferedInputStream(fs.get(key));
		doc = db.parse(new StringBufferInputStream(fs.get(key)));
	
	   
		NodeList nodelist = doc.getElementsByTagName("domain_model_attribute");  // get the child path from current xml
		for (int i = 0; i < nodelist.getLength(); i++) {
			Element dma = (Element) nodelist.item(i);
			NodeList str = dma.getElementsByTagName("typeId");
			Element paramElement = (Element) str.item(0);
			Text paramNode = (Text) paramElement.getFirstChild();
			String str1 = paramNode.getNodeValue();
			if (str1.length() > 2) {

				str1+=".xml";     //path should care

				pathList.add(str1);
				
				readPath(str1);
				//readPath(fs.get(str1));                                            //DFS use recursion
				System.out.println("complexType");	
			}
		}
		
		return pathList;
}
	
	public static void main(String[] args) throws Exception {
		String outFile="./src/sjtu/isl/sax/MyWadl4.xml";
		String path="9bb9c8fa-2045-408e-bcde-cb9c898e25af";
		GenerateWadl gw=new GenerateWadl();
		gw.writeWadl(outFile, path);
	}

}
